package galaxies.starRegions;


import java.util.ArrayList;
import java.util.Random;

import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;

/*
 * Builds arm star regions
 * 
 * Inputs:  Dimensions of a full, ellipsoid-shaped galaxy arm.  Number of stars in the total arm
 * Outputs:  ArrayList of MArmStarRegions, each of which is a sub-segment of the arm, containing:
 * 		1) Dimensions of the region
 * 		2) Number of star locations in the region
 * 		3) Location and rotation of the region
 * 		4) Area of the region (LY^2)
 * 
 * Star regions are used by a galaxy factory to generate stars within their boundaries.
 * 
 * NOTE:  Does not output list of Controllers--MArmStarRegions are directly required by calling FMSpiralGalaxyClass
 */
public class StarRegionSpiralArmModelBuilder {
	
	//private int numStars;
	private Random rand = new Random();
	private boolean direction = rand.nextBoolean();
	//array holds direction of branching segments.  Last segment always branches in direction of rotation ('true')
	private boolean[] branchDirection = {direction, !direction, true};	
	
	public ArrayList<StarRegionSpiralArmModel> createArmStarRegions(double longDim, double shortDim, double numArms) {
		ArrayList<StarRegionSpiralArmModel> regions = new ArrayList<StarRegionSpiralArmModel>();
		
		//double totalArea = 0.0;
		//this.numStars = numStars;
		
		int numJunctions;
		if (numArms == 6) {
			numJunctions = (int) (rand.nextDouble()*2); //0 - 1
		}
		else if (numArms == 4) {
			numJunctions = (int) (rand.nextDouble()*4); //0 - 3
		}
		else if (numArms == 3) {
			numJunctions = (int) (rand.nextDouble()*4); //0 - 3
		}
		else { //numArms == 2
			numJunctions = (int) (rand.nextDouble()*3+1.0); //1 - 3
		}		
		//numJunctions = 3;
		
		//System.out.println("numJunctions= " + numJunctions);
		
		ArrayList<Double> branchPoints = new ArrayList<Double>();
		if (numJunctions > 0) {
			if (numJunctions == 1) {
				branchPoints.add((rand.nextDouble()*0.33+0.33)*longDim); //33 - 66% of dist
			}
			else if (numJunctions == 2) {
				branchPoints.add((rand.nextDouble()*0.10+0.20)*longDim); //20 - 30% of dist
				branchPoints.add((rand.nextDouble()*0.20+0.50)*longDim); //50 - 70% of dist
			}
			else if (numJunctions == 3) {
				branchPoints.add((rand.nextDouble()*0.10+0.20)*longDim); //20 - 30% of dist
				branchPoints.add((rand.nextDouble()*0.15+0.45)*longDim); //45 - 60% of dist
				branchPoints.add((rand.nextDouble()*0.10+0.75)*longDim); //75 - 85% of dist
			}
		}
		
		branchPoints.add(longDim); //not an actual branchPoint, but serves as a "cap" to the sequence
		
		StarRegionSpiralArmModel tempModel1;
		StarRegionSpiralArmModel tempModel2;
		
		//Add first region
		tempModel1 = new StarRegionSpiralArmModel(longDim, shortDim, branchPoints.get(0));
		tempModel1.setLocation(new Vector2f().zero());
		tempModel1.computeBounds();
		regions.add(tempModel1);
		
		//Add any subsequent regions
		double longCurr = longDim;
		double shortCurr = shortDim;
		double spacer = 0.7; //prevent ultra-small branches (i.e. any branch cannot be > 90% of base width)
		
		//System.out.println("longDim= " + longDim);
		//System.out.println("shortDim= " + shortDim);
		Vector2f oldVector = new Vector2f().zero();
		Vector2f tempLocation1;
		Vector2f tempLocation2;
		double lastBranchPoint = 0.0;
		double smallBranchRatio = 0.75; //longDim of small branch as a % of longDim of large branch at a split
		if (branchPoints.size() > 1) {
			for (int i = 0; i < branchPoints.size()-1; i++) {
				//System.out.println("BranchPoint " + i + "= " + branchPoints.get(i));

				double usedPoint = branchPoints.get(i)-lastBranchPoint;
				//double usedPoint = branchPoints.get(i)*longCurr/longDim;			 
				//System.out.println("usedPoint " + i + "= " + usedPoint);

				//y value if we were still following along the full, unbranched ellipse of the arm
				double yFullEllipse = shortCurr*Math.sqrt(1-usedPoint*usedPoint/(longCurr*longCurr));
				//System.out.println("yFullEllipse= " + yFullEllipse);
				//y value randomly chosen somewhere between +/- y at x = branchPoint
				double yDivisionPt = (rand.nextDouble()*2*yFullEllipse - yFullEllipse)*spacer;
				//System.out.println("yDivisionPt= " + yDivisionPt);

				//branch1 dimensions
				double b1 = (yFullEllipse - yDivisionPt)/2;
				double b2 = (yDivisionPt + yFullEllipse)/2;
				//double b1Temp = b1;
				//double b2Temp = b2;
				
				//regularly alternate which side of the branch goes out from the arm
				//Avoids collisions between new branches
				if (branchDirection[i]) { //(i==0) || (i==2)) {
					if (b1 > b2) {
						double b2temp = b2;
						b2 = b1;
						b1 = b2temp;
					}			
				}
				else { //if (i==1) {
					if (b2 > b1) {
						double b1temp = b1;
						b1 = b2;
						b2 = b1temp;
					}		
				}

				double a1 = 0.0;
				double a2 = 0.0;
				double aLong = 0.0;
				double bLong = 0.0;
				if (b1 >= b2) {
					a1 = longCurr - usedPoint;
					a2 = a1*smallBranchRatio;//(longCurr - usedPoint)*(b2/(yFullEllipse)); 
					//b1 = yFullEllipse;
					aLong = a1;
					bLong = yFullEllipse;
					tempLocation1 = new Vector2f(branchPoints.get(i).floatValue(), 0);
					tempLocation2 = new Vector2f(branchPoints.get(i).floatValue(), (float) (yFullEllipse - (2*b1+b2)));
					
				}
				else {					
					a2 = longCurr - usedPoint;
					a1 = a2*smallBranchRatio;//(longCurr - usedPoint)*(b1/(yFullEllipse));
					//b2 = yFullEllipse;
					aLong = a2;
					bLong = yFullEllipse;
					tempLocation1 = new Vector2f(branchPoints.get(i).floatValue(), (float) (yFullEllipse - b1));
					tempLocation2 = new Vector2f(branchPoints.get(i).floatValue(), 0);
				}

				//System.out.println("a1= " + a1);
				//System.out.println("b1= " + b1);

				//System.out.println("a2= " + a2);
				//System.out.println("b2= " + b2);

				
				//Vector2f tempLocation1 = new Vector2f(branchPoints.get(i).floatValue(), (float) (yFullEllipse - b1));
				//Vector2f tempLocation2 = new Vector2f(branchPoints.get(i).floatValue(), (float) (yFullEllipse - (2*b1+b2)));					
				
				//Vector2f tempLocation1 = new Vector2f(0, (float) (yFullEllipse - b1));
				//Vector2f tempLocation2 = new Vector2f(0, (float) (yFullEllipse - (2*b1+b2)));
				//Vector2f location2 = new Vector2f((float) point, (float) (yDivisionPt - b2/2));
				

				Vector2f location1 = tempLocation1.add(oldVector);
				Vector2f location2 = tempLocation2.add(oldVector);
				//System.out.println("location1= " + location1.x + " " + location1.y);
				//System.out.println("location2= " + location2.x + " " + location2.y);
				
				if (a1 >= a2) {
					//tempModel1 = new StarRegionSpiralArmModel(a1, b1, a1);//branchPoints.get(i+1));
					//tempModel1 = new StarRegionSpiralArmModel(a1, b1, branchPoints.get(i+1)-branchPoints.get(i));
					tempModel1 = new StarRegionSpiralArmModel(a1, yFullEllipse, branchPoints.get(i+1)-branchPoints.get(i));
					tempModel2 = new StarRegionSpiralArmModel(a2, b2, a2); //no stop point, branch 2 is smaller
					oldVector = new Vector2f(0, location1.y);
					//location1.y = (float) -yFullEllipse/2;
					tempModel2.setOffsetRotation(-Math.PI/2); //smaller arm is offset, downward					
				}
				else {
					tempModel1 = new StarRegionSpiralArmModel(a1, b1, a1); //no stop point, branch 1 is smaller
					//tempModel2 = new StarRegionSpiralArmModel(a2, b2, a2);//branchPoints.get(i+1));
					//tempModel2 = new StarRegionSpiralArmModel(a2, b2, branchPoints.get(i+1)-branchPoints.get(i));
					tempModel2 = new StarRegionSpiralArmModel(a2, yFullEllipse, branchPoints.get(i+1)-branchPoints.get(i));
					oldVector = new Vector2f(0, location2.y);
					//location2.y = (float) -yFullEllipse/2;
					tempModel1.setOffsetRotation(Math.PI/2); //smaller arm offset upward.
				}			

				tempModel1.setLocation(location1);
				//tempModel1.computeBounds();
				tempModel2.setLocation(location2);
				//tempModel2.computeBounds();

				regions.add(tempModel1);
				regions.add(tempModel2);

				shortCurr = bLong;			
				longCurr = aLong;
				lastBranchPoint = branchPoints.get(i);

				//System.out.println("aCurr= " + longCurr);
				//System.out.println("bCurr= " + shortCurr);

				//System.out.println(" ");		
			}
		}		
		
//		//compute stars per sector
//		//----------------------------------------
//		totalArea = 0.0;
//		for (MArmStarRegion region: regions) {
//			totalArea += region.getArea();
//		}
//		
//		int starsInSector = 0;
//		int placedStars = 0;		
//		for (MArmStarRegion region: regions) {
//			starsInSector = (int) Math.ceil(region.getArea()/totalArea*numStars);
//			System.out.println("");
//			System.out.println("StarsInSector: " + starsInSector);
//			System.out.println("ShortDim: " + region.getShortDim());
//			System.out.println("LongDim: " + region.getLongDim());
//			System.out.println("StopDim: " + region.getStopLongDim());
//			System.out.println("Area: " + region.getArea());
//			System.out.println("TotalArea: " + totalArea);
//			System.out.println("NumStars: " + numStars);
//			System.out.println("");
//			region.setNumStars(starsInSector);
//			placedStars += starsInSector;
//		}
//		
//		System.out.println("StarsInSector: " + starsInSector);
//		
//		//Remove excess stars
//		int diff = placedStars - numStars;		
//		int iMax = regions.size() - 1;
//		int i = 0;		
//		while (diff>0) {
//			i = (int) (rand.nextDouble()*iMax);
//			starsInSector = regions.get(i).getNumStars();
//			regions.get(i).setNumStars(starsInSector-1);
//			diff--;
//		}
		
		return regions;
	}

}
